import numpy as np
import cv2
import glob
from skimage import filters
from src.image_preprocess import img_correct

# import img_correct

def pro_H(img):
    '''
    得到方差投影
    :param img: 所要得到投影的图
    :return: 返回投影列表
    '''
    pro_x = []
    for i in range(img.shape[0]):
        dif = []
        for j in range(img.shape[1]):
            dif.append(img[i][j])
        sum_dif = np.sum(dif)
        pro_x.append(sum_dif)
    return pro_x


def get_threshold(pro, img):
    pro.sort()
    small = []
    for i in range(int(img.shape[0] / 20)):
        small.append(pro[i])
    small = np.mean(small)
    return small


def deal_x(img, pro, th):
    '''

    :param img:
    :param pro:
    :param th:
    :return:
    '''
    for i in range(img.shape[0]):
        if pro[i] < th:
            for j in range(img.shape[1]):
                img[i, j] = 255
        else:
            for j in range(img.shape[1]):
                img[i, j] = 0
    return img


def hist_img(pro):
    '''
    得到投影直方图
    :param pro: 投影列表
    :return: 返回投影直方图
    '''
    max = np.max(pro)
    h_img = np.ones((len(pro), int(max + 1))) * 0
    for i in range(len(pro)):
        cv2.line(h_img, (0, i), (int(pro[i]), i), 255)
    return h_img


def img_normal(mat):
    num = []
    for i in range(mat.shape[0]):
        for j in range(mat.shape[1]):
            num.append(mat[i][j])
    mat_min = min(num)
    mat_max = max(num)
    for i in range(mat.shape[0]):
        for j in range(mat.shape[1]):
            mat[i][j] = int((mat[i][j] - mat_min) / (mat_max - mat_min) * 255)
    return mat


def choose_troughs(pro_trough):
    '''
    得到投影直方图的波谷
    :param pro_trough: 投影直方图
    :return: 返回波谷的y坐标，波谷投影值列表
    '''
    troughs = []
    peaks = []
    for idx in range(6, len(pro_trough) - 6):
        trough = []
        peak = []
        for i in range(5):
            if pro_trough[idx - i] < pro_trough[idx] > pro_trough[idx + i]:
                peak.append([idx, pro_trough[idx]])
            if pro_trough[idx - i] > pro_trough[idx] < pro_trough[idx + i]:
                trough.append([idx, pro_trough[idx]])
        if len(peak) > 3: peaks.append([idx, pro_trough[idx]])
        if len(trough) > 3: troughs.append([idx, pro_trough[idx]])
    return troughs, peaks


def get_mask(pro, img):
    mask = np.ones((img.shape[0], img.shape[1]), dtype=np.uint8) * 255
    line = []
    for i in pro:
        line.append(i[0])
    for i in line:
        cv2.line(mask, (0, i), (img.shape[1], i), 0)
    masks = []
    binary, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    for i in contours:
        black = np.zeros((img.shape[0], img.shape[1]), dtype=np.uint8)
        i = [i]
        cv2.drawContours(black, i, -1, 255, -1)
        masks.append(black)
    return masks


def bw(mask):
    for i in range(mask.shape[0]):
        for j in range(mask.shape[1]):
            if mask[i][j] != 0:
                mask[i][j] = 1
    return mask


def draw_mask(img, masks):
    for i in masks:
        r, b, g = cv2.split(img)
    img_masks = []
    for i in masks:
        i = bw(i)
        r_1 = r * i
        g_1 = g * i
        b_1 = b * i
        img_mask = cv2.merge([r_1, g_1, b_1])
        img_masks.append(img_mask)
    return img_masks


def area_threshold(gray_img):
    """
    区域二值化
    :param gray_img: 边界图
    :return: 二值图
    """
    imgs = []
    img_mat = np.zeros(gray_img.shape, np.uint8)
    for i in range(3):
        img = gray_img[int(gray_img.shape[0] / 3 * i):int(gray_img.shape[0] / 3 * (i + 1)), 0:gray_img.shape[1]]
        thresh_img = filters.threshold_otsu(img)
        ret, img = cv2.threshold(img, thresh_img, 255, cv2.THRESH_BINARY)
        imgs.append(img)
    for j in range(len(imgs)):
        img_mat[int(gray_img.shape[0] / 3 * j):int(gray_img.shape[0] / 3 * (j + 1)), 0:gray_img.shape[1]] = imgs[j]
    return img_mat


def deal_img(img):
    img_mat = np.zeros(img.shape, np.uint16)
    a = img.shape[0]
    b = img.shape[1]
    c = min([a, b])
    for i in range(5):
        if int(c / 2) % 2 == 1:
            c = int(c / 2)
        else:
            c = int(c / 2) + 1
        ker = (c, c)
        img_blur = cv2.GaussianBlur(img, ker, 0.0, sigmaY=5.0)
        img_diff = img_blur - img
        y = cv2.Sobel(img_blur, cv2.CV_16S, 0, 1)
        absY = cv2.convertScaleAbs(y)
        # cv2.imshow('absyt', absY)
        absY = area_threshold(absY)
        img_mat = img_mat + absY
    img_mat = area_threshold(img_mat)
    bw = np.zeros(img.shape, np.uint8)
    ret, contours, hierarchy = cv2.findContours(img_mat, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    for i in contours:
        i_max = np.max(i[0][0])
        if cv2.contourArea(i) > img.shape[1] * 5:
            i = [i]
            cv2.drawContours(bw, i, -1, (255, 255, 255), -1)
    # img_mat = img_normal(img_mat)
    # img_mat = np.array(img_mat, np.uint8)
    # cv2.imshow('abyt', bw)
    # cv2.waitKey()
    return bw


def find_max_peak(pro):
    '''
    获得方差投影最小点
    :param pro:投影列表
    :return:最小点的y坐标和投影值
    '''
    mins = []
    for i in pro:
        mins.append(i[1])
    min_value = np.min(mins)
    max_value = np.max(mins)
    max = [i for i in pro if (i[1] == max_value)]
    for i in max:
        i[1] = max_value
        max = i
    return max


def smooth(pro):
    keras = [0.5, 0.7, 0.9, 1.0, 0.9, 0.7, 0.5]
    pro_smooth = []
    pro_smooth.append(50)
    pro_smooth.append(50)
    pro_smooth.append(50)
    for i in range(2, len(pro) - 3):
        pro_c = [pro[i - 3], pro[i - 2], pro[i - 1], pro[i], pro[i + 1], pro[i + 2], pro[i + 3]]
        sum = 0
        for i in range(len(pro_c)):
            smoot = pro_c[i] * keras[i]
            sum = sum + smoot
        ave = sum / 7
        pro_smooth.append(ave)
    pro_smooth.append(50)
    pro_smooth.append(50)
    pro_smooth.append(50)
    return pro_smooth


def seg_mask_x(pro, img):
    '''
    对x方向的图进行切割
    :param pro: 关键点列表
    :param img: 原图
    :return: 切割后的矩阵列表
    '''
    # print(pro)
    image = []
    for i in range(len(pro) - 1):
        img_0 = img[pro[i]:pro[i + 1], 0: img.shape[1]]
        image.append(img_0)
    return image


def choose_point(pro_peak, img):
    points = []
    line = []
    pro_peak = sort_line(pro_peak)
    line.append(pro_peak[0][0])
    for i in range(1, len(pro_peak)):
        if pro_peak[i][0] - pro_peak[i - 1][0] > img.shape[0] / 15:
            line.append(pro_peak[i][0])
    if len(line) > 1:
        if line[0] > img.shape[0] / 10:
            points.append([0, 0, img.shape[1], int(line[0])])
        for i in range(1, len(line) - 1):
            points.append([0, int(line[i - 1]), img.shape[1], int(line[i])])
        if line[len(line) - 1] < img.shape[0] / 10 * 9:
            points.append([0, int(line[len(line) - 2]), img.shape[1], int(line[len(line) - 1])])
    return points


def draw_line(pro, img):
    for i in pro:
        cv2.line(img, (0, i - 5), (img.shape[1], i - 5), (0, 255, 255), 5)
    return img


def sort_line(pro):
    pro_x = []
    pro_line = []
    for i in pro:
        pro_x.append(i[0])
    pro_x = np.sort(pro_x)
    for i in range(len(pro_x)):
        if pro_x[i] == pro[i][0]:
            pro_line.append(pro[i])
    return pro_line


def normalization(pro):
    max = np.max(pro)
    min = np.min(pro)
    nor_pro = []
    for i in pro:
        nor = (i - min) / (max - min) * 100
        nor_pro.append(nor)
    return nor_pro


def area(pro_trough, pro_peak):
    area_peak = []
    areas = []
    area_trough = []
    for i in range(len(pro_peak) - 1):
        for j in range(len(pro_trough) - 1):
            if pro_peak[i][0] < pro_trough[j][0] < pro_peak[i + 1][0]:
                max = np.max([pro_peak[i + 1][1], pro_peak[i][1]])
                weigh = abs(max - pro_trough[j][1])
                area = (pro_peak[i + 1][0] - pro_peak[i][0]) * weigh
                areas.append(area)
    area_range = (np.max(areas) - np.min(areas)) / 5
    mid = np.min(areas) + area_range
    for i in range(len(pro_peak) - 1):
        for j in range(len(pro_trough) - 1):
            if pro_peak[i][0] < pro_trough[j][0] < pro_peak[i + 1][0]:
                max = np.max([pro_peak[i + 1][1], pro_peak[i][1]])
                weigh = abs(max - pro_trough[j][1])
                area_pro_trough = (pro_peak[i + 1][0] - pro_peak[i][0]) * weigh
                if area_pro_trough > mid:
                    area_peak.append(pro_trough[j])
                    area_trough = [[pro_trough[j], area_pro_trough]]
    return area_peak, area_trough


def seg_img(img_1):
    """
    图像预处理
    :param img_1:处理图片
    :return: 判断图像返回值个数（1,4）
                1:返回整张图
                4:1.矫正图像切割点
                  2.矫正后图像
                  3.变换矩阵
                  4.剩余图像
    """
    result = img_correct.i_correct(img_1)
    if len(result) != 1:
        p_img = cv2.cvtColor(result['1'], cv2.COLOR_BGR2Lab)
        l, a, b = cv2.split(p_img)
        p_img = deal_img(l)
        gray_1 = pro_H(p_img)
        gray_smooth = smooth(gray_1)
        gray_normalization = normalization(gray_smooth)
        # #寻找波峰波谷
        for i in range(10):
            gray_smooth = smooth(gray_smooth)
            gray_normalization = normalization(gray_smooth)
        gray_smooth_trough, gray_smooth_peak = choose_troughs(gray_normalization)
        gray_hist = hist_img(gray_normalization)
        if len(gray_smooth_peak) > 2:
            point = choose_point(gray_smooth_peak, p_img)
            fin = {'1': point, '2': result['1'], '3': result['2'], '4': result['3']}
            return fin
        else:
            point = [[0, 0, img_1.shape[1], img_1.shape[0]]]
            return point
        # cv2.imshow('hist', gray_hist)
    else:
        point = [[0, 0, img_1.shape[1], img_1.shape[0]]]
        return point
